package com.example.demo;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * @author linjingze
 * @date 2021/3/16 1:27 下午
 */
public class BigDecimalUtils {


    public static BigDecimal mul(BigDecimal v1, BigDecimal v2) {
        return mul(v1, v2, 2);
    }

    public static BigDecimal mul100(BigDecimal v1) {
        return mul(v1, new BigDecimal("100"), 2);
    }

    public static BigDecimal mulKeep4Scale(BigDecimal v1, BigDecimal v2) {
        return mul(v1, v2, 4);
    }

    public static BigDecimal mulKeep2Scale(BigDecimal v1, BigDecimal v2) {
        return mul(v1, v2, 2);
    }

    public static BigDecimal add(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).add(toBigDecimalStr(v2));
    }

    public static BigDecimal add(BigDecimal... values){
        if (Objects.isNull(values)) {
            return BigDecimal.ZERO;
        }else {
            BigDecimal value = values[0];
            BigDecimal result = toBigDecimalStr(value);

            for(int i = 1; i < values.length; ++i) {
                value = values[i];
                if (null != value) {
                    result = result.add(toBigDecimalStr(value));
                }
            }

            return result;
        }
    }

    public static BigDecimal subtract(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).subtract(toBigDecimalStr(v2));
    }
    public static BigDecimal subtractToKeep2Scale(BigDecimal v1, BigDecimal v2) {
        return toKeep2Scale(subtract(v1, v2));
    }

    public static BigDecimal sub(BigDecimal... values) {
        if (Objects.isNull(values)) {
            return BigDecimal.ZERO;
        }else {
            BigDecimal value = values[0];
            BigDecimal result = toBigDecimalStr(value);

            for(int i = 1; i < values.length; ++i) {
                value = values[i];
                if (null != value) {
                    result = result.subtract(toBigDecimalStr(value));
                }
            }

            return result;
        }

    }

    public static BigDecimal mul(BigDecimal v1, BigDecimal v2, int scale) {
        return toBigDecimalStr(v1).multiply(toBigDecimalStr(v2)).setScale(scale, RoundingMode.HALF_UP);
    }

    public static BigDecimal min(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) > 0 ? v2 : v1;
    }
    public static BigDecimal max(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) > 0 ? v1 : v2;
    }


    public static BigDecimal toBigDecimalStr(BigDecimal val) {
        return val == null ? BigDecimal.ZERO : new BigDecimal(String.valueOf(val.doubleValue()));
    }

    public static Long toLong(BigDecimal val) {
        return val == null ? 0L : val.longValue();
    }

    public static BigDecimal toBigDecimal(Long val) {
        return val == null ? BigDecimal.ZERO : new BigDecimal(val);
    }

    public static BigDecimal toBigDecimal(Integer val) {
        return val == null ? BigDecimal.ZERO : new BigDecimal(val);
    }

    public static BigDecimal toBigDecimal(String val) {
        return val == null || "".equals(val) ? BigDecimal.ZERO : new BigDecimal(val);
    }


    public static BigDecimal toKeep2Scale(BigDecimal val) {
        return toBigDecimalStr(val).setScale(2, RoundingMode.HALF_UP);
    }

    public static BigDecimal toKeepScale(BigDecimal val, int scale) {
        return toBigDecimalStr(val).setScale(scale, RoundingMode.HALF_UP);
    }

    /**
     * 不处理 / by zero
     */
    public static BigDecimal div(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 2, RoundingMode.HALF_UP);
    }

    public static BigDecimal divKeep8Scale(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 8, RoundingMode.HALF_UP);
    }

    public static BigDecimal divKeep6Scale(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 6, RoundingMode.HALF_UP);
    }

    public static BigDecimal divKeep4Scale(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 4, RoundingMode.HALF_UP);
    }
    public static BigDecimal divKeep3Scale(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 3, RoundingMode.HALF_UP);
    }

    public static BigDecimal divKeep2Scale(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divide(toBigDecimalStr(v2), 2, RoundingMode.HALF_UP);
    }

    public static BigDecimal[] divideAndRemainder(BigDecimal v1, BigDecimal v2) {
        return toBigDecimalStr(v1).divideAndRemainder(toBigDecimalStr(v2));
    }

    public static boolean equals(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) == 0;
    }

    public static boolean notEquals(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) != 0;
    }
    
    public static boolean greater(BigDecimal v1, BigDecimal v2){
        return v1.compareTo(v2) > 0;
    }

    public static boolean greaterThanOrEqual(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) >= 0;
    }

    public static boolean greaterThanZero(BigDecimal v) {
        return v.compareTo(BigDecimal.ZERO) > 0;
    }

    public static boolean greaterThanZeroIgnoreNull(BigDecimal v) {
        return v != null && v.compareTo(BigDecimal.ZERO) > 0;
    }
    public static boolean lessThanZeroIgnoreNull(BigDecimal v) {
        return v != null && v.compareTo(BigDecimal.ZERO) < 0;
    }

    public static boolean notEqZeroIgnoreNull(BigDecimal v) {
        return v != null && v.compareTo(BigDecimal.ZERO) != 0;
    }

    public static boolean greaterEqZero(BigDecimal v) {
        return v.compareTo(BigDecimal.ZERO) >= 0;
    }

    public static boolean lessEqZero(BigDecimal v) {
        return v.compareTo(BigDecimal.ZERO) <= 0;
    }

    public static boolean eqZero(BigDecimal v) {
        return equals(v, BigDecimal.ZERO);
    }

    public static boolean notEqZero(BigDecimal v) {
        return !eqZero(v);
    }

    public static boolean eqZeroOrNull(BigDecimal v) {
        return v == null || equals(v, BigDecimal.ZERO);
    }

    public static boolean equalsZero(BigDecimal v) {
        return equals(v, BigDecimal.ZERO);
    }

    public static boolean lessThanZero(BigDecimal v) {
        return v.compareTo(BigDecimal.ZERO) < 0;
    }

    public static boolean lessThan(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) < 0;
    }
    public static boolean lessThanOrEqual(BigDecimal v1, BigDecimal v2) {
        return v1.compareTo(v2) <= 0;
    }

    /**
     * 获取小数点
     */
    public static int getNumberOfDecimalPlace(BigDecimal value) {
        final String s = value.toPlainString();
        final int index = s.indexOf('.');
        if (index < 0) {
            return 0;
        }
        return s.length() - 1 - index;
    }

    /**
     * 取小数点，跳过末尾0
     */
    public static int getNumberOfDecimalPlaceTrailingZeros(BigDecimal value) {
        final String s = value.stripTrailingZeros().toPlainString();
        final int index = s.indexOf('.');
        if (index < 0) {
            return 0;
        }
        return s.length() - 1 - index;
    }

    public static String toPlainString(BigDecimal val) {

        return val.stripTrailingZeros().toPlainString();
    }


    public static String toStringDefault(BigDecimal val, String defaultVal){
        return val == null ? defaultVal : toPlainString(val);
    }
    
    public static BigDecimal add(List<BigDecimal> bigDecimalList) {
        BigDecimal start = BigDecimal.ZERO;
        if (isEmpty(bigDecimalList)) {
            return start;
        }
        for (BigDecimal bigDecimal : bigDecimalList) {
            start = toBigDecimalStr(start).add(toBigDecimalStr(bigDecimal));
        }
        return start;
    }

    public static BigDecimal zeroReturnZero(BigDecimal val, Supplier<BigDecimal> bigDecimalSupplier) {
        if (eqZero(val)) {
            return BigDecimal.ZERO;
        }
        return bigDecimalSupplier.get();
    }

    /**
     * 校验字段串是否数字
     *
     * @param bigDecimalValue 字符类型的值
     * @return 是否合法
     */
    public static boolean isLegalDecimal(String bigDecimalValue) {
        return bigDecimalValue.matches("-?[0-9]+.*[0-9]*");
    }


    static boolean isEmpty(final Collection<?> c) {
        return c == null || c.isEmpty();
    }

    /**
     * 获取相反数
     */
    public static BigDecimal negate(BigDecimal amount){
        if(amount == null){
            return null;
        }
        return amount.negate();
    }

}
